package main

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"os"
	"os/exec"
	"os/user"
	"path"
	"runtime"
	"strings"
	"syscall"
	"time"
)

type Result struct {
	Success bool   `json:"success"`
	Msg     string `json:"msg"`
	Data    any    `json:"data"`
}

// =======================================================================

var configFileName string = "config.json"

const ImageDirName string = "gote-images"

func initDataPath() {
	// 默认保存文件夹创建
	_, err := os.Stat(CurrentSetting.DataPath)
	if err != nil {
		if os.IsNotExist(err) {
			err = os.Mkdir(CurrentSetting.DataPath, os.ModePerm)
			if err != nil {
				panic(err)
			}
		} else {
			panic(err)
		}
	}
}

func ReadSetting() (*Setting, error) {
	user, err := user.Current()
	if err != nil {
		return nil, NewCustomError("userCurrent error", err)
	}
	homeDir := user.HomeDir
	configFileDir := path.Join(homeDir, ".config", "gote")
	configPath := path.Join(configFileDir, configFileName)

	_, err = os.Stat(configFileDir)
	if err != nil {
		if os.IsNotExist(err) {
			err = os.Mkdir(configFileDir, os.ModePerm)
			if err != nil {
				return nil, NewCustomError("创建配置文件夹失败", err)
			}
		}
	}

	_, err = os.Stat(configPath)
	if err != nil {
		if os.IsNotExist(err) {

			setting := &Setting{
				AccessPassword:     "",
				FileAccessPassword: "",
				UseAccessPassword:  false,
				DataPath:           path.Join(homeDir, "gote-data"),
				Port:               10086,
			}
			bs, err := json.Marshal(setting)
			if err != nil {
				return nil, NewCustomError("序列化setting失败", err)
			}
			err = os.WriteFile(configPath, bs, os.ModePerm)
			if err != nil {
				return nil, NewCustomError("写入配置文件失败", err)
			}
			return setting, nil
		}
		return nil, NewCustomError("配置文件stat失败", err)
	}

	bs, err := os.ReadFile(configPath)
	if err != nil {
		return nil, NewCustomError("读取配置文件失败", err)
	}
	var setting Setting
	err = json.Unmarshal(bs, &setting)
	if err != nil {
		return nil, NewCustomError("反序列配置文件失败", err)
	}
	return &setting, nil
}
func initImagePath() {
	// 初始化图片保存目录
	_, err := os.Stat(path.Join(CurrentSetting.DataPath, ImageDirName))
	if err != nil {
		if os.IsNotExist(err) {
			// create image path
			err = os.Mkdir(path.Join(CurrentSetting.DataPath, ImageDirName), os.ModePerm)
			if err != nil {
				panic(err)
			}
		} else {
			panic(err)
		}
	}
}

func WriteSetting(bs []byte) error {
	user, err := user.Current()
	if err != nil {
		return NewCustomError("userCurrent error", err)
	}
	homeDir := user.HomeDir
	configFileDir := path.Join(homeDir, ".config", "gote")
	configPath := path.Join(configFileDir, configFileName)

	err = os.WriteFile(configPath, bs, os.ModePerm)
	if err != nil {
		return NewCustomError("写配置错误", err)
	}
	initDataPath()
	initImagePath()
	return nil
}

func Fail(rsp *http.ResponseWriter, content string) {
	errResult, _ := json.Marshal(Result{Success: false, Msg: content})
	(*rsp).Write(errResult)
}

func Ok(rsp *http.ResponseWriter, data any) {
	errResult, _ := json.Marshal(Result{Success: true, Msg: "ok", Data: data})
	(*rsp).Write(errResult)
}

// 新建文件
func CreateFile(p string) error {
	switch runtime.GOOS {
	case "linux":
		fallthrough
	case "darwin":
		if err := exec.Command("touch", p).Run(); err != nil {
			return err
		}

	case "windows":
		if err := exec.Command("type", "nul>", p).Run(); err != nil {
			return err
		}
	}
	return nil
}

// 新建文件夹
func CreateFolder(p string) error {
	switch runtime.GOOS {
	case "linux":
		fallthrough
	case "darwin":
		if err := exec.Command("mkdir", "-p", p).Run(); err != nil {
			return err
		}

	case "windows":
		if err := exec.Command("mkdir", p).Run(); err != nil {
			return err
		}
	}
	return nil
}

// 重命名文件
func RenameItem(old string, new string) error {
	switch runtime.GOOS {
	case "linux":
		fallthrough
	case "darwin":
		if err := exec.Command("mv", old, new).Run(); err != nil {
			return err
		}

	case "windows":
		if err := exec.Command("rename", old, new).Run(); err != nil {
			return err
		}
	}
	return nil
}

// 删除文件/文件夹
func DeleteItem(p string, isDir bool) error {
	switch runtime.GOOS {
	case "linux":
		fallthrough
	case "darwin":
		if err := exec.Command("rm", "-fr", p).Run(); err != nil {
			return err
		}

	case "windows":
		if isDir {
			if err := exec.Command("rmdir", "/s", "/q", p).Run(); err != nil {
				return err
			}
		} else {
			if err := exec.Command("del", "-f", p).Run(); err != nil {
				return err
			}
		}
	}
	return nil
}

func StartWith(target string, substring string) bool {
	if target == "" {
		return false
	}
	s := strings.Split(target, "")
	return s[0] == substring
}

// 加密函数
func Encrypt(key []byte, plaintextBytes []byte) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	// 创建加密容器（GCM 模式）
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 生成随机 Nonce（必须唯一）
	nonce := make([]byte, gcm.NonceSize())
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	// 加密并返回 Base64 编码结果
	ciphertext := gcm.Seal(nonce, nonce, plaintextBytes, nil)
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// 解密函数
func Decrypt(key []byte, encryptedText string) (string, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return "", err
	}

	// 解码 Base64
	ciphertext, err := base64.StdEncoding.DecodeString(encryptedText)
	if err != nil {
		return "", err
	}

	// 创建 GCM 解密器
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	// 提取 Nonce
	nonceSize := gcm.NonceSize()
	if len(ciphertext) < nonceSize {
		return "", errors.New("ciphertext too short")
	}
	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]

	// 解密
	plaintextBytes, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return "", err
	}

	return string(plaintextBytes), nil
}

// getCreationTime 尝试获取文件的创建时间
func GetCreationTime(info os.FileInfo) time.Time {
	// 在某些操作系统上（如 Windows），可以通过 Sys() 获取底层信息
	if stat, ok := info.Sys().(*syscall.Stat_t); ok {
		// 在 Linux 上，可能需要使用 stat.Birthtime
		// 在 macOS 上，可能需要使用 stat.Ctimespec
		// 注意：不同平台实现可能不同，这里以 Linux 为例
		return time.Unix(stat.Ctim.Sec, stat.Ctim.Nsec)
	}
	return time.Time{} // 如果无法获取，返回零值
}

func FormatDateTime(t time.Time) string {
	return t.Local().Format("2006-01-02 15:04:05")
}
